package com.example.train.common.aspect;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

@Aspect
@Component
public class LogAspect {
    //aspect是切面的意思
    public LogAspect(){
        System.out.println("Common LogAspect");
    }
    private final static Logger LOG= LoggerFactory.getLogger(LogAspect.class);

    //下面是一个切点方法
    @Pointcut("execution(public * com.example..*Controller.*(..))")
    public void controllerPointcut(){
        //意为对这个包内所有以controller为后缀的类的所有方法的所有版本的都做处理
    }
    @Before("controllerPointcut()")
    public void doBefore(JoinPoint joinPoint){

        //生成日志流水号，用MDC插入
        //功能已在interceptor中使用
        //MDC.put("LOG_ID",System.currentTimeMillis()+ RandomUtil.randomString(3));

        //打印请求日志
        ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request=attributes.getRequest();
        Signature signature=joinPoint.getSignature();
        String name=signature.getName();

        //打印请求信息
        LOG.info("--------开始--------");
        LOG.info("请求地址:{} {}",request.getRequestURL().toString(),request.getLocalAddr());
        LOG.info("类名方法:{} {}",signature.getDeclaringType(),name);
        LOG.info("远程地址:{}",request.getRemoteAddr());

        //打印请求参数
        Object[] args=joinPoint.getArgs();

        //排除特殊类型参数，比如文件
        Object[] arguments=new Object[args.length];
        for(int i=0;i<args.length;i++){
            if(args[i] instanceof ServletRequest
                    || args[i] instanceof ServletResponse
                    || args[i] instanceof MultipartFile){
                continue;
            }
            arguments[i]=args[i];
        }

        //排除特殊字段，敏感字段或者太长的不予显示，起到加密作用
        String[] excludeProperties={"mobile"};
        PropertyPreFilters filters=new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludeFilter=filters.addFilter();
        excludeFilter.addExcludes(excludeProperties);
        LOG.info("请求参数:{}", JSONObject.toJSONString(arguments,excludeFilter));

    }
    @Around("controllerPointcut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime=System.currentTimeMillis();
        Object result=proceedingJoinPoint.proceed();

        String[] excludeProperties={"mobile"};
        PropertyPreFilters filters=new PropertyPreFilters();
        PropertyPreFilters.MySimplePropertyPreFilter excludeFilter=filters.addFilter();
        excludeFilter.addExcludes(excludeProperties);

        LOG.info("返回结果:{}",JSONObject.toJSONString(result,excludeFilter));
        LOG.info("--------结束 耗时:{} ms --------",System.currentTimeMillis()-startTime);

        return result;
    }
}
